use async_trait::async_trait;
use log::{error, info};
use ssh2::Session;
use std::collections::HashMap; // Add this import
use std::io;
use std::io::Read;
use std::pin::Pin;
use std::task::{Context, Poll};
use std::time::Duration;
use tokio::io::{AsyncRead, AsyncWrite, ReadBuf};
use tokio::net::TcpStream;

// Define a trait for status checks
#[async_trait]
pub trait StatusChecker {
    async fn check(&self) -> io::Result<String>;
}

#[derive(Clone)]
pub struct ServiceInfo {
    pub display_name: String,
    pub status: String,
}

// Implement the online status checker
pub struct OnlineChecker {
    pub connection_type: String, // Make the field public
    pub addr: String,            // Make the field public
    pub port: u16,               // Make the field public
    pub timeout: Duration,       // Make the field public
    pub services: HashMap<String, ServiceInfo>, // Add a mapping for service names and statuses
                                 // 添加服务的key对应的名称
}

impl OnlineChecker {
    // 新增一个方法来检查每个服务的状态
    pub async fn check_services(&self) -> io::Result<HashMap<String, ServiceInfo>> {
        let mut results = HashMap::new();
        let addr = "192.168.1.10";
        let username = "root";
        let password = "orangepi";

        // 创建 SSH 会话
        info!("Connecting to SSH server at {}:22", addr);
        let tcp = tokio::net::TcpStream::connect(format!("{}:22", addr)).await?;
        let mut session = Session::new().unwrap();
        session.set_tcp_stream(tcp);
        session.handshake().unwrap();
        session.userauth_password(username, password).unwrap();

        if !session.authenticated() {
            error!("SSH authentication failed for user {}", username);
            return Err(io::Error::new(
                io::ErrorKind::PermissionDenied,
                "SSH authentication failed",
            ));
        }
        info!("SSH authentication successful for user {}", username);

        for (service_name, service_info) in &self.services {
            info!("Checking status for service: {}", service_name);
            let status = match self.check_service_status(service_name, &session).await {
                Ok(service_status) => service_status,
                Err(_) => "异常".to_string(),
            };
            results.insert(
                service_name.clone(),
                ServiceInfo {
                    display_name: service_info.display_name.clone(),
                    status: status,
                },
            );
        }
        Ok(results)
    }

    async fn check_service_status(
        &self,
        service_name: &str,
        session: &Session,
    ) -> io::Result<String> {
        info!(
            "Executing command to check status of service: {}",
            service_name
        );

        // 执行 systemctl status 命令
        let mut channel = session.channel_session().unwrap();
        channel
            .exec(&format!("systemctl status {}", service_name))
            .unwrap();

        let mut output = Vec::new(); // 使用 Vec<u8> 来存储输出
        channel.read_to_end(&mut output).unwrap(); // 从 channel 读取数据
        channel.send_eof().unwrap();
        channel.wait_close().unwrap();

        // 将 Vec<u8> 转换为 String
        let output_string = String::from_utf8_lossy(&output).to_string();

        // 打印输出信息
        info!("Output for service {}: {}", service_name, output_string);

        // 检查输出是否包含 "active"
        if output_string.contains("code=exited") {
            info!("Service {} is dead", service_name);
            Ok("已停止".to_string())
        } else if output_string.contains("inactive") {
            info!("Service {} is inactive", service_name);
            Ok("异常".to_string())
        } else if output_string.contains("active") || output_string.contains("activating") {
            info!("Service {} is active", service_name);
            Ok("正常".to_string())
        } else if output_string.contains("Active: inactive") {
            Ok("已停止".to_string())
        } else {
            info!("Service {} is not active", service_name);
            Ok("异常".to_string())
        }
    }
}

#[async_trait]
impl StatusChecker for OnlineChecker {
    async fn check(&self) -> io::Result<String> {
        match create_connection(
            &self.connection_type,
            self.addr.clone(),
            self.port,
            self.timeout,
        )
        .await
        {
            Ok(_) => Ok("在线".to_string()),
            Err(_) => Ok("离线".to_string()),
        }
    }
}

// 定义通信接口
#[async_trait]
pub trait Connection: AsyncRead + AsyncWrite + Send + Unpin {
    async fn connect(addr: String, port: u16, timeout: Duration) -> io::Result<Self>
    where
        Self: Sized;
    async fn shutdown(&mut self) -> io::Result<()>;
}

// TcpStream实现
#[async_trait]
impl Connection for TcpStream {
    async fn connect(addr: String, port: u16, timeout: Duration) -> io::Result<Self> {
        let addr = format!("{}:{}", addr, port);
        match tokio::time::timeout(timeout, TcpStream::connect(&addr)).await {
            Ok(result) => result,
            Err(_) => Err(io::Error::new(
                io::ErrorKind::TimedOut,
                "connection timed out",
            )),
        }
    }

    async fn shutdown(&mut self) -> io::Result<()> {
        self.shutdown().await
    }
}

// 创建一个网络管理器
pub struct NetworkManager {
    connection_type: String,
    addr: String,
    port: u16,
    timeout: Duration,
}

impl NetworkManager {
    pub fn new(connection_type: String, addr: String, port: u16, timeout: Duration) -> Self {
        Self {
            connection_type,
            addr,
            port,
            timeout,
        }
    }

    pub async fn connect(&self) -> io::Result<impl Connection> {
        let mut retries = 3; // 设置重试次数
        while retries > 0 {
            match create_connection(
                &self.connection_type,
                self.addr.clone(),
                self.port,
                self.timeout,
            )
            .await
            {
                Ok(conn) => return Ok(conn),
                Err(e) => {
                    retries -= 1;
                    if retries == 0 {
                        return Err(e);
                    }
                    // 等待一段时间后重试
                    tokio::time::sleep(Duration::from_secs(2)).await;
                }
            }
        }
        Err(io::Error::new(
            io::ErrorKind::Other,
            "Failed to connect after retries",
        ))
    }
}

// 创建连接的工厂函数
pub async fn create_connection(
    connection_type: &str,
    addr: String,
    port: u16,
    timeout: Duration,
) -> io::Result<impl Connection> {
    match connection_type {
        "tcp" => TcpStream::connect(format!("{}:{}", addr, port)).await,
        "mock" => {
            // 这里可以实现模拟连接的逻辑
            unimplemented!()
        }
        _ => Err(io::Error::new(
            io::ErrorKind::InvalidInput,
            "Invalid connection type",
        )),
    }
}

// ------------------------------------- MOCK -------------------------------------
// Implement other status checkers as needed
// For example, a mock status checker
pub struct MockChecker;

#[async_trait]
impl StatusChecker for MockChecker {
    async fn check(&self) -> io::Result<String> {
        // Implement mock logic here
        Ok("模拟状态".to_string())
    }
}

// MockConnection 结构体
pub struct MockConnection {
    is_connected: bool,
    should_fail: bool,
}

impl MockConnection {
    pub fn new(should_fail: bool) -> Self {
        MockConnection {
            is_connected: false,
            should_fail,
        }
    }
}

// 实现 AsyncRead trait
impl AsyncRead for MockConnection {
    fn poll_read(
        self: Pin<&mut Self>,
        _cx: &mut Context<'_>,
        _buf: &mut ReadBuf<'_>,
    ) -> Poll<io::Result<()>> {
        Poll::Ready(Ok(()))
    }
}

// 实现 AsyncWrite trait
impl AsyncWrite for MockConnection {
    fn poll_write(
        self: Pin<&mut Self>,
        _cx: &mut Context<'_>,
        _buf: &[u8],
    ) -> Poll<Result<usize, io::Error>> {
        Poll::Ready(Ok(_buf.len()))
    }

    fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Result<(), io::Error>> {
        Poll::Ready(Ok(()))
    }

    fn poll_shutdown(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Result<(), io::Error>> {
        Poll::Ready(Ok(()))
    }
}

// 为 MockConnection 实现 Connection trait
#[async_trait]
impl Connection for MockConnection {
    async fn connect(addr: String, port: u16, _timeout: Duration) -> io::Result<Self> {
        let should_fail = addr == "fail" || port == 0;
        let mut conn = MockConnection::new(should_fail);

        if should_fail {
            Err(io::Error::new(
                io::ErrorKind::ConnectionRefused,
                "mock connection failed",
            ))
        } else {
            conn.is_connected = true;
            Ok(conn)
        }
    }

    async fn shutdown(&mut self) -> io::Result<()> {
        self.is_connected = false;
        Ok(())
    }
}
